/*
# File    :   blocklink.cs
# Date    :   Sat, May 25, 2019  9:59:02 PM
# ref     :   https://www.cnblogs.com/huangxincheng/p/3581322.html
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {
            List<int> list = new List<int>() { 8959, 30290, 18854, 7418, 28749, 17313, 5877, 27208, 15771, 4335 };

            //list.Clear();

            //List<int> list = new List<int>();

            //for (int i = 0; i < 100; i++)
            //{
            //    var num = new Random((int)DateTime.Now.Ticks).Next(0, short.MaxValue);

            //    System.Threading.Thread.Sleep(1);

            //    list.Add(num);
            //}


            BlockLinkList blockList = new BlockLinkList();

            foreach (var item in list)
            {
                blockList.Add(item);
            }

            //var b = blockList.IsExist(333);
            //blockList.GetCount();

            Console.WriteLine(blockList.Get(27208));


            #region MyRegion
            ////随机删除150个元素
            //for (int i = 0; i < 5000; i++)
            //{
            //    var rand = new Random((int)DateTime.Now.Ticks).Next(0, list.Count);

            //    System.Threading.Thread.Sleep(2);

            //    Console.WriteLine("\n**************************************\n当前要删除元素：{0}", list[rand]);

            //    blockList.Remove(list[rand]);

            //    Console.WriteLine("\n\n");

            //    if (blockList.GetCount() == 0)
            //    {
            //        Console.Read();
            //        return;
            //    }
            //} 
            #endregion

            Console.Read();
        }
    }

    public class BlockLinkList
    {
        BlockLinkNode blockLinkNode = null;

        public BlockLinkList()
        {
            //初始化节点
            blockLinkNode = new BlockLinkNode()
            {
                list = new List<int>(),
                next = null,
                prev = null
            };
        }

        /// <summary>
        /// 定义块状链表的总长度
        /// </summary>
        private int total;

        public class BlockLinkNode
        {
            /// <summary>
            /// 指向前一个节点的指针
            /// </summary>
            public BlockLinkNode prev;

            /// <summary>
            /// 指向后一个节点的指针
            /// </summary>
            public BlockLinkNode next;

            /// <summary>
            /// 链表中的数组
            /// </summary>
            public List<int> list;
        }

        /// <summary>
        /// 判断指定元素是否存在
        /// </summary>
        /// <param name="num"></param>
        /// <returns></returns>
        public bool IsExist(int num)
        {
            var isExist = false;

            var temp = blockLinkNode;

            while (temp != null)
            {
                //判断是否在该区间内
                if (temp.list.Count > 0 && num >= temp.list[0] && num <= temp.list[temp.list.Count - 1])
                {
                    isExist = temp.list.IndexOf(num) > 0 ? true : false;

                    return isExist;
                }

                temp = temp.next;
            }

            return isExist;
        }

        public string Get(int num)
        {
            var blockIndex = 0;
            var arrIndex = 0;

            var temp = blockLinkNode;

            while (temp != null)
            {
                //判断是否在该区间内
                if (temp.list.Count > 0 && num >= temp.list[0] && num <= temp.list[temp.list.Count - 1])
                {
                    arrIndex = temp.list.IndexOf(num);

                    return string.Format("当前数据在第{0}块中的{1}个位置", blockIndex, arrIndex);
                }

                blockIndex = blockIndex + 1;
                temp = temp.next;
            }

            return string.Empty;
        }

        /// <summary>
        /// 将元素加入到块状链表中
        /// </summary>
        /// <param name="num"></param>
        public BlockLinkNode Add(int num)
        {
            return Add(blockLinkNode, num);
        }

        /// <summary>
        /// 添加元素只会进行块状链表的分裂
        /// </summary>
        /// <param name="node"></param>
        /// <param name="num"></param>
        /// <returns></returns>
        private BlockLinkNode Add(BlockLinkNode node, int num)
        {
            if (node == null)
            {
                return node;
            }
            else
            {
                /*
                 *  第一步：找到指定的节点
                 */
                if (node.list.Count == 0)
                {
                    node.list.Add(num);

                    total = total + 1;

                    return node;
                }

                //下一步：再比较是否应该分裂块
                var blockLen = (int)Math.Ceiling(Math.Sqrt(total)) * 2;

                //如果该节点的数组的最后位置值大于插入值，则此时我们找到了链表的插入节点，
                //或者该节点的next=null，说明是最后一个节点，此时也要判断是否要裂开
                if (node.list[node.list.Count - 1] > num || node.next == null)
                {
                    node.list.Add(num);

                    //最后进行排序下，当然可以用插入排序解决，O(N)搞定
                    node.list = node.list.OrderBy(i => i).ToList();

                    //如果该数组里面的个数大于2*blockLen，说明已经过大了，此时需要对半分裂
                    if (node.list.Count > blockLen)
                    {
                        //先将数据插入到数据库
                        var mid = node.list.Count / 2;

                        //分裂处的前段部分
                        var firstList = new List<int>();

                        //分裂后的后段部分
                        var lastList = new List<int>();

                        //可以在插入点处分裂，也可以对半分裂(这里对半分裂)
                        firstList.AddRange(node.list.Take(mid));
                        lastList.AddRange(node.list.Skip(mid).Take(node.list.Count - mid));


                        //开始分裂节点，需要新开辟一个新节点
                        var nNode = new BlockLinkNode();

                        nNode.list = lastList;
                        nNode.next = node.next;
                        nNode.prev = node;

                        //改变当前节点的next和list
                        node.list = firstList;
                        node.next = nNode;
                    }

                    total = total + 1;

                    return node;
                }

                return Add(node.next, num);
            }
        }

        /// <summary>
        /// 从块状链表中移除元素
        /// </summary>
        /// <param name="num"></param>
        /// <returns></returns>
        public BlockLinkNode Remove(int num)
        {
            return Remove(blockLinkNode, num);
        }

        /// <summary>
        /// 从块状链表中移除元素,涉及到合并
        /// </summary>
        /// <param name="node"></param>
        /// <param name="num"></param>
        /// <returns></returns>
        private BlockLinkNode Remove(BlockLinkNode node, int num)
        {
            if (node == null)
            {
                return node;
            }
            else
            {
                //第一步： 判断删除元素是否在该节点内
                if (node.list.Count > 0 && num >= node.list[0] && num <= node.list[node.list.Count - 1])
                {
                    //定义改节点的目的在于防止remove方法假删除的情况发生
                    var prevcount = node.list.Count;

                    node.list.Remove(num);

                    total = total - (prevcount - node.list.Count);

                    //下一步： 判断是否需要合并节点
                    var blockLen = (int)Math.Ceiling(Math.Sqrt(total) / 2);

                    //如果当前节点的数组个数小于 blocklen的话，那么此时改节点需要和后一个节点进行合并
                    //如果该节点时尾节点，则放弃合并
                    if (node.list.Count < blockLen)
                    {
                        if (node.next != null)
                        {
                            node.list.AddRange(node.next.list);

                            //如果下一个节点的下一个节点不为null，则将下下个节点的prev赋值
                            if (node.next.next != null)
                                node.next.next.prev = node;

                            node.next = node.next.next;
                        }
                        else
                        {
                            //最后一个节点不需要合并，如果list=0，则直接剔除该节点
                            if (node.list.Count == 0)
                            {
                                if (node.prev != null)
                                    node.prev.next = null;

                                node = null;
                            }
                        }
                    }

                    return node;
                }

                return Remove(node.next, num);
            }
        }

        /// <summary>
        /// 获取块状链表中的所有个数
        /// </summary>
        /// <returns></returns>
        public int GetCount()
        {
            int count = 0;

            var temp = blockLinkNode;

            Console.Write("各节点数据个数为：");

            while (temp != null)
            {
                count += temp.list.Count;

                Console.Write(temp.list.Count + ",");

                temp = temp.next;
            }

            Console.WriteLine("总共有:{0} 个元素", count);

            return count;
        }
    }
}
